#include <casensorfullbi/CASensorFullBiE.h>

// ***********************************************************************

// class EDROOMTopContext

// ***********************************************************************



	// CONSTRUCTORES***********************************************

CASensorFullBi::EDROOMTopContext::EDROOMTopContext (CASensorFullBi &act, bool_t & EDROOMpVarVCrcOk, FrameTypeReceived_t & EDROOMpVarVFrameSend, CEDROOMTimer & EDROOMpVarVIdTimer, int & EDROOMpVarVMessageNumber, int & EDROOMpVarVMessageReceived, CDSignal & EDROOMpVarVSignalFrame, CEDROOMPOOLCDFrame & EDROOMpPoolCDFrame, CEDROOMPOOLCDSignal & EDROOMpPoolCDSignal ):

	EDROOMcomponent(act)
	,Msg(EDROOMcomponent.Msg)
	,MsgBack(EDROOMcomponent.MsgBack)
	,ReTx(EDROOMcomponent.ReTx)
	,Timer(EDROOMcomponent.Timer)
	,Ssi(EDROOMcomponent.Ssi)
	, VCrcOk ( EDROOMpVarVCrcOk )
	, VFrameSend ( EDROOMpVarVFrameSend )
	, VIdTimer ( EDROOMpVarVIdTimer )
	, VMessageNumber ( EDROOMpVarVMessageNumber )
	, VMessageReceived ( EDROOMpVarVMessageReceived )
	, VSignalFrame ( EDROOMpVarVSignalFrame )
	, CEDROOMPoolCDFrame ( EDROOMpPoolCDFrame )
	, EDROOMPoolCDSignal ( EDROOMpPoolCDSignal )
 {

}

CASensorFullBi::EDROOMTopContext::EDROOMTopContext ( EDROOMTopContext &contex ):

	EDROOMcomponent(contex.EDROOMcomponent),
	Msg(contex.Msg),
	MsgBack(contex.MsgBack)
	,ReTx(contex.ReTx)
	,Timer(contex.Timer)
	,Ssi(contex.Ssi)
	, VCrcOk ( contex.VCrcOk )
	, VFrameSend ( contex.VFrameSend )
	, VIdTimer ( contex.VIdTimer )
	, VMessageNumber ( contex.VMessageNumber )
	, VMessageReceived ( contex.VMessageReceived )
	, VSignalFrame ( contex.VSignalFrame )
	, CEDROOMPoolCDFrame ( contex.CEDROOMPoolCDFrame )
	, EDROOMPoolCDSignal ( contex.EDROOMPoolCDSignal )
 {

}

	// EDROOMSearchContextTrans********************************************

bool CASensorFullBi::EDROOMTopContext::EDROOMSearchContextTrans(TEDROOMTransId &edroomCurrentTrans){

	bool edroomValidMsg=false; 

	 switch(Msg->signal){

		 case ( EDROOMSignalDestroy ): 

			 edroomValidMsg=true;
			 edroomCurrentTrans.distanceToContext = 0 ;
			 edroomCurrentTrans.localId = -1 ;
			 break;

	}

	return(edroomValidMsg);

}

	// Funciones Definidas por el usuario  ****************************

void	CASensorFullBi::EDROOMTopContext::FBuildAck(byte_t *finalFrame)

{
	struct ssi_link_layer_signal_frame_info_t ackFrame;
	strcpy((char*)ackFrame.radio_id,"000001");
	ackFrame.sensor_id=MASK_BIDIRECTIONAL_SSI;
	ackFrame.flags=MASK_ACK_SSI;
	strcpy((char*)ackFrame.reserved,"000000");
	ssi_link_layer_build_signal_frame(finalFrame,&ackFrame);

}



void	CASensorFullBi::EDROOMTopContext::FBuildDiscovery(byte_t *finalFrame)
{
	struct ssi_link_layer_signal_frame_info_t discoveryFrame;
	strcpy((char*)discoveryFrame.radio_id,"000001");
	discoveryFrame.sensor_id=MASK_BIDIRECTIONAL_SSI;
	discoveryFrame.flags=MASK_DISCOVERY_SSI;
	strcpy((char*)discoveryFrame.reserved,"000000");
	ssi_link_layer_build_signal_frame(finalFrame,&discoveryFrame);

	if (VMessageNumber % 15 == 0)//TODO: para probocar fallo
	{
		finalFrame[15]=finalFrame[15]+1;
	}

}
 




void	CASensorFullBi::EDROOMTopContext::FIntToChar(TEDROOMInt32 num,byte_t * cConvert)

{
	byte_t aux;
	TEDROOMInt32 i=0;
	TEDROOMInt32 j;
	do
	{ 
		cConvert[i++]= (num % 10) + '0';
		num=num/10;
	}
	while (num>0);
	cConvert[i--]='\0';
	j=0;
	for (;i>j;i--,j++)
	{
		aux=cConvert[i];
		cConvert[i]=cConvert[j];
		cConvert[j]=aux;
	}
}



void	CASensorFullBi::EDROOMTopContext::FListening()

{
	//printf("SENSOR: Listening\n");
}



void	CASensorFullBi::EDROOMTopContext::FReceiveData()


{
	ReTx.cancelTimer(VIdTimer);
	CDFrame & varCDFrame = *(CDFrame *)Msg->data;

	//VMessageNumber++;//
 	VFrameSend=get_frame_type(varCDFrame.dataFrame);
	VCrcOk=ssi_link_layer_check_data_frame_crc(varCDFrame.dataFrame);

}



void	CASensorFullBi::EDROOMTopContext::FRtxRandom()


{
	//Pr_Time	interval(2.00); // Declare time var with an initial value in seconds
	//float tRxTx= 90.0 +(rand() % 5);//FINAL
	float tRxTx= 1.0 +(float)(rand() % 10)/10;
	Pr_Time	interval(tRxTx); // Declare time var with an initial value in seconds
	//Pr_Time	interval(0.10); // Declare time var with an initial value in seconds

	VIdTimer=ReTx.InformIn( interval, EDROOMprioNormal );
 
//	interval.GetTime();
//	//printf("interval \%f", interval.Secns());

}



void	CASensorFullBi::EDROOMTopContext::FSendFrame()

{

	CDSignal * ap_CDSignal = EDROOMPoolCDSignal.AllocData();
	*ap_CDSignal=VSignalFrame;
	Ssi.send(SSignalFrame, EDROOMprioNormal, ap_CDSignal, &EDROOMPoolCDSignal);
	VMessageNumber++;//para el test

}



void	CASensorFullBi::EDROOMTopContext::FSTimeSend()

{
		VFrameSend=FrameTypeIsSSIDefault;


		FBuildDiscovery(VSignalFrame.signalFrame);

		//Pr_Time	interval(1.00); // Declare time var with an initial value in seconds
		Pr_Time	interval(0.01); // Declare time var with an initial value in seconds
		Timer.InformIn( interval, EDROOMprioNormal );

}



void	CASensorFullBi::EDROOMTopContext::FStoreFrame()

{
 	CDFrame & varCDFrame = *(CDFrame *)Msg->data;
	FILE *fich;
	byte_t data[32];
	TEDROOMInt32 length;
	CDSignal * ap_CDSignal = EDROOMPoolCDSignal.AllocData();
 
	//printf("NUMERO DE MENSAJE %d\n",VMessageReceived);
	// Complete Data 
	FBuildAck(ap_CDSignal->signalFrame);
	// send new Msg
	Ssi.send(SSignalFrame, EDROOMprioNormal, ap_CDSignal, &EDROOMPoolCDSignal);
	fich=fopen("FDwFrames.jpg","ab");
	ssi_link_layer_get_data(varCDFrame.dataFrame,data);
	length = ssi_link_layer_get_data_length(varCDFrame.dataFrame);
	if (fich!=NULL)
	{				
				fwrite(data, 1,length, fich);
				fclose(fich);
	}

	if (VMessageReceived==1211)
	{
	   FCheckFiles();
	   exit(0);
	}
	VMessageReceived++;
}




bool_t	CASensorFullBi::EDROOMTopContext::GIsAck()

{
 
 return VCrcOk && (VFrameSend==FrameTypeIsSSIAck);

 
}



bool_t	CASensorFullBi::EDROOMTopContext::GNotIsAck()

{
  return VCrcOk && ((VFrameSend==FrameTypeIsSSIData)||(VFrameSend==FrameTypeIsSSIDiscovery));
}



void	CASensorFullBi::EDROOMTopContext::FReceiveSignal()



{
	ReTx.cancelTimer(VIdTimer);
	CDSignal & varCDSignal = *(CDSignal *)Msg->data;

	//VMessageNumber++;//
 	VFrameSend=get_frame_type(varCDSignal.signalFrame);
	VCrcOk=ssi_link_layer_check_signal_frame_crc(varCDSignal.signalFrame);


 
}



void	CASensorFullBi::EDROOMTopContext::FCheckFiles()


{
	printf("SENSOR : CHECK\n");
	FILE *originFile,*finalFile;
	bool_t ok=true;
	byte_t originBuffer[50], finalBuffer[50];

   finalFile=fopen("FDwFrames.jpg","rb");
   originFile=fopen("ODwFrames.jpg","rb");
   if (finalFile!=NULL && originFile!=NULL)
   {
      do
		{
		   for (TEDROOMInt32 i =0; i< 50; i++)
		   {
			   originBuffer[i]=0;
			   finalBuffer[i]=0;
		   }
		   fread(originBuffer, 1,1, originFile);
		   fread(finalBuffer, 1,1, finalFile);
		   if(originBuffer[0]!=finalBuffer[0])
		   {
			ok=false;
		   }
		} while (!feof(originFile) && !feof(finalFile));
	   fclose(originFile);
	   fclose(finalFile);
   }
   else
   {
	   ok=false;
	   if (finalFile!=NULL)
	   {
		   fclose(finalFile);
	   }
	   if (originFile!=NULL)
	   {
		   fclose(originFile);
	   }
   }

   if (ok)
   {
   	printf("TEST DOWN FRAMES: OK\n");
   }
   else
   {
   	printf("TEST DOWN FRAMES: ERROR\n");
   }
}



	//*****Pools

	//CEDROOMPOOLCDFrame

CASensorFullBi::EDROOMTopContext::CEDROOMPOOLCDFrame::CEDROOMPOOLCDFrame(unsigned int elemCount, CDFrame* pMem, bool_t * pMemMarks):CEDROOMProtectedMemoryPool(elemCount, pMem, pMemMarks, sizeof (CDFrame)){;}

CDFrame *	CASensorFullBi::EDROOMTopContext::CEDROOMPOOLCDFrame::AllocData(){
	return(CDFrame*)CEDROOMProtectedMemoryPool::AllocData();
}

	//CEDROOMPOOLCDSignal

CASensorFullBi::EDROOMTopContext::CEDROOMPOOLCDSignal::CEDROOMPOOLCDSignal(unsigned int elemCount, CDSignal* pMem, bool_t * pMemMarks):CEDROOMProtectedMemoryPool(elemCount, pMem, pMemMarks, sizeof (CDSignal)){;}

CDSignal *	CASensorFullBi::EDROOMTopContext::CEDROOMPOOLCDSignal::AllocData(){
	return(CDSignal*)CEDROOMProtectedMemoryPool::AllocData();
}



// ***********************************************************************

// class EDROOMTopState

// ***********************************************************************



	// CONSTRUCTOR*************************************************

CASensorFullBi::EDROOMTopState::EDROOMTopState (CASensorFullBi &act, CEDROOMMemory *pEDROOMMemory  ):
	  EDROOMTopContext( act , VCrcOk, VFrameSend, VIdTimer, VMessageNumber, VMessageReceived, VSignalFrame,CEDROOMPoolCDFrame,EDROOMPoolCDSignal )
	, VCrcOk ( false )
	, VFrameSend ( FrameTypeIsSSIDefault )
	, VIdTimer (   )
	, VMessageNumber ( 1 )
	, VMessageReceived ( 1 )
	, CEDROOMPoolCDFrame ( 10, pEDROOMMemory->poolCDFrame, pEDROOMMemory->poolMarkCDFrame)
	, EDROOMPoolCDSignal ( 10, pEDROOMMemory->poolCDSignal, pEDROOMMemory->poolMarkCDSignal)
{

}

	// EDROOMBehaviour**********************************************

void CASensorFullBi::EDROOMTopState::EDROOMBehaviour(){

	TEDROOMTransId edroomCurrentTrans;

	edroomCurrentTrans = EDROOMIllegada();

	do{

		switch(edroomCurrentTrans.localId){

			case(Init):
				edroomNextState = Standby;
				break;
			case(ReceiveData):
				FReceiveData();

				EDROOMcomponent.EDROOMTraceStateEntry();

				if( GNotIsAck() ){
					FStoreFrame();
					edroomCurrentTrans.localId = ReceiveData_IsData;
					edroomNextState = Standby;
				 } 
				else{
					edroomCurrentTrans.localId = ReceiveData_CrcFail;
					edroomNextState = Standby;
				 } 
				EDROOMcomponent.EDROOMTraceTrans(edroomCurrentTrans, Msg->signal);
				break;
			case(SendFrame):
				FSendFrame();

				EDROOMcomponent.EDROOMTraceStateEntry();

				if( GIsAck() ){
					edroomCurrentTrans.localId = SendFrame_SendAck;
					edroomNextState = Standby;
				 } 
				else{
					edroomCurrentTrans.localId = SendFrame_SendData;
					edroomNextState = Listening;
				 } 
				EDROOMcomponent.EDROOMTraceTrans(edroomCurrentTrans, Msg->signal);
				break;
			case(ReTxData):
				edroomNextState = Standby;
				break;
			case(ReceiveSignal):
				FReceiveSignal();

				EDROOMcomponent.EDROOMTraceStateEntry();

				if( GIsAck() ){
					edroomCurrentTrans.localId = ReceiveSignal_IsAck;
					edroomNextState = Standby;
				 }
				else{
					edroomCurrentTrans.localId = ReceiveSignal_CrcFail;
					edroomNextState = Standby;
				 }
				EDROOMcomponent.EDROOMTraceTrans(edroomCurrentTrans, Msg->signal);
				break;
		}

		EDROOMcomponent.EDROOMTraceStateEntry();

		EDROOMcomponent.EDROOMTraceStateEntry();

		switch(edroomNextState){

			case(I):
				edroomCurrentTrans=EDROOMIllegada();
				break;

			case(Standby):
				FSTimeSend();
				edroomCurrentTrans=EDROOMStandbyllegada();
				break;

			case(Listening):
				FRtxRandom();
				edroomCurrentTrans=EDROOMListeningllegada();
				break;

		}

		EDROOMcomponent.EDROOMTraceStateExit();

		edroomCurrentState=edroomNextState;

	}while(Msg->signal != EDROOMSignalDestroy);

}



	// Inicio**********************************************

void CASensorFullBi::EDROOMTopState::EDROOMInicio(){

edroomCurrentState=I;

}



//	 ***********************************************************************

//	 llegada SubEstado I

//	 ***********************************************************************



TEDROOMTransId CASensorFullBi::EDROOMTopState::EDROOMIllegada(){

	TEDROOMTransId edroomCurrentTrans;

	edroomCurrentTrans.localId = Init;
	edroomCurrentTrans.distanceToContext = 0;
	EDROOMcomponent.EDROOMTraceTrans(edroomCurrentTrans, 0);

	return(edroomCurrentTrans);

}



	// ***********************************************************************

	// llegada SubEstado Hoja Standby

	// ***********************************************************************



TEDROOMTransId CASensorFullBi::EDROOMTopState::EDROOMStandbyllegada(){

	TEDROOMTransId edroomCurrentTrans;

	int edroomValidMsg=false;

	do{

		EDROOMNuevoMens ();

		switch(Msg->signal){

			case (EDROOMSignalTimeout): 

				 if ( *Msg->GetPInterface() == Timer) {

					edroomCurrentTrans.localId = SendFrame;
					edroomCurrentTrans.distanceToContext = 0 ;
					edroomValidMsg=true;
				 }

				break;

		};

		if (!edroomValidMsg) edroomValidMsg = EDROOMSearchContextTrans(edroomCurrentTrans);

	} while (!edroomValidMsg);

	EDROOMcomponent.EDROOMTraceTrans(edroomCurrentTrans, Msg->signal);

	return(edroomCurrentTrans);

}



	// ***********************************************************************

	// llegada SubEstado Hoja Listening

	// ***********************************************************************



TEDROOMTransId CASensorFullBi::EDROOMTopState::EDROOMListeningllegada(){

	TEDROOMTransId edroomCurrentTrans;

	int edroomValidMsg=false;

	do{

		EDROOMNuevoMens ();

		switch(Msg->signal){

			case (SDataFrame): 

				 if ( *Msg->GetPInterface() == Ssi) {

					edroomCurrentTrans.localId = ReceiveData;
					edroomCurrentTrans.distanceToContext = 0 ;
					edroomValidMsg=true;
				 }

				break;

			case (EDROOMSignalTimeout): 

				 if ( *Msg->GetPInterface() == ReTx) {

					edroomCurrentTrans.localId= ReTxData;
					edroomCurrentTrans.distanceToContext = 0;
					edroomValidMsg=true;
				 }

				break;

			case (SSignalFrame):

				 if ( *Msg->GetPInterface() == Ssi) {

					edroomCurrentTrans.localId = ReceiveSignal;
					edroomCurrentTrans.distanceToContext = 0 ;
					edroomValidMsg=true;
				 }

				break;

		};

		if (!edroomValidMsg) edroomValidMsg = EDROOMSearchContextTrans(edroomCurrentTrans);

	} while (!edroomValidMsg);

	EDROOMcomponent.EDROOMTraceTrans(edroomCurrentTrans, Msg->signal);

	return(edroomCurrentTrans);

}



